package com.lemon.cloud.mp.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.lemon.cloud.comm.constants.CommonConstants;
import com.lemon.cloud.mp.config.WxMpContextHolder;
import com.lemon.cloud.mp.config.WxMpInitConfigService;
import com.lemon.cloud.mp.entity.WxAccount;
import com.lemon.cloud.mp.entity.WxAccountFans;
import com.lemon.cloud.mp.mapper.WxAccountFansMapper;
import com.lemon.cloud.mp.mapper.WxAccountMapper;
import com.lemon.cloud.mp.service.WxAccountFansService;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.WxMpUserService;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import me.chanjar.weixin.mp.bean.result.WxMpUserList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class WxAccountFansServiceImpl extends ServiceImpl<WxAccountFansMapper, WxAccountFans> implements WxAccountFansService {

    @Autowired
    private WxAccountMapper wxAccountMapper;


    @Override
    public Boolean syncAccountFans(String appId) {
        WxAccount wxAccount = wxAccountMapper
                .selectOne(Wrappers.<WxAccount>query().lambda().eq(WxAccount::getAppid, appId));

        // 获取操作微信接口类
        WxMpService wxMpService = WxMpInitConfigService.getMpServices().get(appId);
        WxMpUserService wxMpUserService = wxMpService.getUserService();
        // 根据公众号查询已同步用户openid 查询最新的一条 (注意不能按订阅时间排序)
        String finalNextOpenId = queryNextOpenId(appId);
        fetchUser(finalNextOpenId, wxAccount, wxMpUserService);

        log.info("公众号 {} 粉丝同步完成", wxAccount.getName());
        return Boolean.TRUE;
    }

    /**
     * 获取微信用户
     *
     * @param nextOpenid      下一组开始的openid
     * @param wxAccount       公众号信息
     * @param wxMpUserService mp操作类
     */
    private void fetchUser(String nextOpenid, WxAccount wxAccount, WxMpUserService wxMpUserService) {
        try {
            WxMpUserList wxMpUserList = wxMpUserService.userList(nextOpenid);
            // openId 分组 每组 100个 openid,API限制单次10000个
            List<List<String>> openIdsList = CollUtil.split(wxMpUserList.getOpenids(), CommonConstants.HUNDRED).stream()
                    .filter(CollUtil::isNotEmpty).collect(Collectors.toList());
            // 处理每个分组. 调用查询用户信息
            for (List<String> openIdList : openIdsList) {
                log.info("开始批量获取用户信息 {}", openIdList);
                List<WxAccountFans> wxAccountFansList = new ArrayList<>();
                wxMpUserService.userInfoList(openIdList).forEach(wxMpUser -> {
                    WxAccountFans wxAccountFans = buildDbUser(wxAccount, wxMpUser);
                    wxAccountFansList.add(wxAccountFans);
                });
                this.saveOrUpdateBatch(wxAccountFansList);
                log.info("批量插入用户信息完成 {}", openIdList);
            }
            // 如果nextOpenId 不为空，则继续获取
            if (StrUtil.isNotBlank(wxMpUserList.getNextOpenid())) {
                fetchUser(wxMpUserList.getNextOpenid(), wxAccount, wxMpUserService);
            }
        } catch (Exception e) {
            log.warn("同步微信公众号 {} 粉丝异常 {}", wxAccount.getName(), e.getMessage());
            // 失败重试逻辑
            String finalNextOpenId = queryNextOpenId(wxAccount.getAppid());
            fetchUser(finalNextOpenId, wxAccount, wxMpUserService);
        }

    }

    /**
     * 构建数据库存取对象
     *
     * @param wxAccount 公众号信息
     * @param wxMpUser  用户微信信息
     */
    private WxAccountFans buildDbUser(WxAccount wxAccount, WxMpUser wxMpUser) {
        WxAccountFans wxAccountFans = new WxAccountFans();
        wxAccountFans.setOpenid(wxMpUser.getOpenId());
        wxAccountFans.setSubscribeStatus(String.valueOf(BooleanUtil.toInt(wxMpUser.getSubscribe())));

        // 2020-11-25 部分用户订阅时间为空，跳过此字段处理
        if (ObjectUtil.isNotEmpty(wxMpUser.getSubscribeTime())) {
            wxAccountFans.setSubscribeTime(LocalDateTime
                    .ofInstant(Instant.ofEpochMilli(wxMpUser.getSubscribeTime() * 1000L), ZoneId.systemDefault()));
        }
        wxAccountFans.setNickname(wxMpUser.getNickname());
        //wxAccountFans.setGender(String.valueOf(wxMpUser.getSex()));
        wxAccountFans.setLanguage(wxMpUser.getLanguage());
        //wxAccountFans.setCountry(wxMpUser.getCountry());
        //wxAccountFans.setProvince(wxMpUser.getProvince());
        //wxAccountFans.setCity(wxMpUser.getCity());
        wxAccountFans.setHeadimgUrl(wxMpUser.getHeadImgUrl());
        wxAccountFans.setRemark(wxMpUser.getRemark());
        wxAccountFans.setWxAccountId(wxAccount.getId());
        wxAccountFans.setWxAccountAppid(wxAccount.getAppid());
        wxAccountFans.setWxAccountName(wxAccount.getName());
        return wxAccountFans;
    }

    /**
     * 查询当前公众号最后插入的openId
     *
     * @param appId 公众号标识
     * @return openid / null
     */
    private String queryNextOpenId(String appId) {
        WxAccountFans last = baseMapper.selectOne(Wrappers.<WxAccountFans>query().lambda()
                .eq(WxAccountFans::getWxAccountAppid, appId).orderByDesc(WxAccountFans::getCreateTime).last("limit 0,1"));
        if (ObjectUtil.isNotNull(last)) {
            return last.getOpenid();
        }
        return null;
    }


    /**
     * 网页授权获取的用户详情信息
     *
     * @param appId
     * @param wxOAuth2UserInfo
     */
    @Override
    public WxAccountFans saveOrUpdateByOauth2(String appId, WxOAuth2UserInfo wxOAuth2UserInfo) {
        WxAccountFans wxAccountFans = baseMapper.selectOne(
                Wrappers.<WxAccountFans>lambdaUpdate().eq(WxAccountFans::getOpenid, wxOAuth2UserInfo.getOpenid()));

        if (wxAccountFans == null) {
            wxAccountFans = new WxAccountFans();
        }
        wxAccountFans.setOpenid(wxOAuth2UserInfo.getOpenid());
        wxAccountFans.setNickname(wxOAuth2UserInfo.getNickname());
        wxAccountFans.setGender(String.valueOf(wxOAuth2UserInfo.getSex()));
        wxAccountFans.setCountry(wxOAuth2UserInfo.getCountry());
        wxAccountFans.setProvince(wxOAuth2UserInfo.getProvince());
        wxAccountFans.setCity(wxOAuth2UserInfo.getCity());
        wxAccountFans.setHeadimgUrl(wxOAuth2UserInfo.getHeadImgUrl());
        wxAccountFans.setSnapshotUser(wxOAuth2UserInfo.getSnapshotUser());
        wxAccountFans.setUnionId(wxOAuth2UserInfo.getUnionId());
        wxAccountFans.setPrivileges(StrUtil.join(StrUtil.COMMA, Lists.newArrayList(wxOAuth2UserInfo.getPrivileges())));

        WxAccount wxAccount = wxAccountMapper
                .selectOne(Wrappers.<WxAccount>lambdaQuery().eq(WxAccount::getAppid, appId));
        wxAccountFans.setWxAccountId(wxAccount.getId());
        wxAccountFans.setWxAccountAppid(wxAccount.getAppid());
        wxAccountFans.setWxAccountName(wxAccount.getName());
        this.saveOrUpdate(wxAccountFans);
        return wxAccountFans;
    }
}
